

const list = [
  {id: 19, parentId: 0},  // index 0
  {id: 15, parentId: 19}, // index 1
  {id: 18, parentId: 15}, // index 2
  {id: 17, parentId: 16}, // index 3
  {id: 16, parentId: 0},  // index 4
]

const result=convert(list,'parentId','id',0)

function convert(list, parentKey, currentKey, rootValue) {
  // 创建根节点对象，用于存储最终的树结构
  const res = {
    [currentKey]: rootValue,  // 设置根节点的ID值（通常是0）
    children: []              // 初始化根节点的子节点数组
  };

  let processedCount = 0;     // 计数器：记录已经成功处理的节点数量
  let shouldContinue = true;  // 标志位：控制是否继续循环处理

  // 主循环：当还有未处理的节点且上一轮有处理成功时继续
  while (processedCount < list.length && shouldContinue) {
    shouldContinue = false;  // 重置标志位，假设本轮不会有处理
    
    // 遍历原始数组中的每个节点
    list.forEach((item, index) => {
      if (!item) return;  // 如果节点已被处理（设为null），则跳过
      
      // 检查当前节点是否是根节点的直接子节点
      if (item[parentKey] === res[currentKey]) {
        // 将节点添加到根节点的children数组中（创建副本并初始化children）
        res.children.push({ ...item, children: [] });
        list[index] = null;     // 标记该节点为已处理
        processedCount++;       // 增加已处理计数
        shouldContinue = true;  // 标记本轮有处理成功，需要继续循环
      } else if (findAndAttach(item, index, res.children)) {
        // 如果不是根节点的直接子节点，尝试在现有树结构中查找其父节点
        shouldContinue = true;  // 如果找到并挂载成功，标记需要继续循环
      }
    });
  }

  // 递归查找函数：在给定的节点数组中查找并挂载子节点
  function findAndAttach(item, originalIndex, nodes) {
    // 在当前层级的节点数组中查找目标节点的父节点
    const parentIndex = nodes.findIndex(node => node[currentKey] === item[parentKey]);
    
    // 如果找到了父节点
    if (parentIndex !== -1) {
      // 将当前节点添加到父节点的children数组中
      nodes[parentIndex].children.push({ ...item, children: [] });
      list[originalIndex] = null;  // 标记原始数组中的对应节点为已处理
      processedCount++;            // 增加已处理计数
      return true;                 // 返回成功标志
    }

    // 如果当前层级没找到父节点，递归到每个节点的子节点中继续查找
    for (const node of nodes) {
      // 递归调用，在子节点的children数组中继续查找
      if (findAndAttach(item, originalIndex, node.children)) {
        return true;  // 如果在子节点中找到，返回成功标志
      }
    }

    // 如果所有地方都没找到父节点，返回失败标志
    return false;
  }

  // 返回构建完成的树结构
  return res;
}
